package chess;

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class GameRunner extends JFrame implements ActionListener{

	private static final long serialVersionUID = 1L;

	public static final int X = 8;
	public static final int Y = 8;

	private JPanel panel, jp, introPanel;
	private JFrame frame, introFrame;
	private static JButton[][] button;
	private JMenuItem menuNew, menuExit;
	public static Grid board;
	public static Piece currentP;
	public static LastMove lastMove = new LastMove();
	private JButton knight, bishop, rook, queen, PButton1, PButton2;
	private static JFrame promoFrame;
	private Set<Coordinate> lastCoords= new HashSet<Coordinate>();
	private static Player comp= null;
	//private static Player user= null;
	
	static boolean whiteTurn = true;	

	public final static Color brown = new Color(130,80,50);
	public static boolean somethingSelected = false;
	private static Coordinate kingCoords = null;


	public static void main(String[] args) 
	{
		/*SwingUtilities.invokeLater(new Runnable() {
			public void run () {
				new GameRunner();
			}
		});*/
		new GameRunner();

	}

	public GameRunner() {
		super("Chess");
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		
		panel = new JPanel(new GridLayout(X, Y));
		button = new JButton[X][Y];

		panel.setSize(400,400);
		frame = new JFrame("Chess");
		frame.add(panel);
		frame.setSize(400, 400);
		frame.setLocation(300,150);  
		addMenu();
		construct();
		newGame();
		frame.setVisible(true);
		welcome();
		promoPawn();
	}
	
	public void welcome() {
		introPanel = new JPanel();
		JLabel label = new JLabel("Welcome to Chess!");
		PButton1 = new JButton("One-Player");
		PButton2 = new JButton("Two-Player");
		PButton1.addActionListener(this);
		PButton2.addActionListener(this);
		introPanel.add(label);
		introPanel.add(PButton1);
		introPanel.add(PButton2);
		introFrame = new JFrame("Chess");
		introFrame.add(introPanel);
		introFrame.setSize(200, 150);
		introFrame.setLocation(400,300);
		introFrame.setVisible(true);
	}

	public void construct() {
		for(int j=0; j<Y; j++) {
			for(int i=0; i<X; i++) {
				button[i][j] = new JButton("");
				button[i][j].addActionListener(this);
				if((i+j)%2==0) button[i][j].setBackground(Color.white);
				else button[i][j].setBackground(new Color(130,80,50));
				panel.add(button[i][j]);
			}
		}
		
	}

	public void newGame() {
		ImageIcon box;
		String path = null;
		String file = null;
		board = new Grid();

		/*board.setPieceToCoordinate(new Coordinate(0,0), new Rook("BRook","Rook",Color.BLACK, new Coordinate(0,0)));
		board.setPieceToCoordinate(new Coordinate(1,0), new Knight("BKnight","Knight",Color.BLACK, new Coordinate(1,0)));
		board.setPieceToCoordinate(new Coordinate(2,0), new Bishop("BBishop","Bishop",Color.BLACK, new Coordinate(2,0)));
		board.setPieceToCoordinate(new Coordinate(3,0), new Queen("BQueen","Queen",Color.BLACK, new Coordinate(3,0)));
		board.setPieceToCoordinate(new Coordinate(4,0), new King("BKing","King",Color.BLACK, new Coordinate(4,0)));
		board.setPieceToCoordinate(new Coordinate(5,0), new Bishop("BBishop","Bishop",Color.BLACK, new Coordinate(5,0)));
		board.setPieceToCoordinate(new Coordinate(6,0), new Knight("BKnight","Knight",Color.BLACK, new Coordinate(6,0)));
		board.setPieceToCoordinate(new Coordinate(7,0), new Rook("BRook","Rook",Color.BLACK, new Coordinate(7,0)));
		for (int i=0; i<X; i++)
			board.setPieceToCoordinate(new Coordinate(i,1), new Pawn("BPawn","Pawn",Color.BLACK, new Coordinate(i,1)));

		board.setPieceToCoordinate(new Coordinate(0,7), new Rook("WRook","Rook",Color.WHITE, new Coordinate(0,7)));
		board.setPieceToCoordinate(new Coordinate(1,7), new Knight("WKnight","Knight",Color.WHITE, new Coordinate(1,7)));
		board.setPieceToCoordinate(new Coordinate(2,7), new Bishop("WBishop","Bishop",Color.WHITE, new Coordinate(2,7)));
		board.setPieceToCoordinate(new Coordinate(3,7), new Queen("WQueen","Queen",Color.WHITE, new Coordinate(3,7)));
		board.setPieceToCoordinate(new Coordinate(4,7), new King("WKing","King",Color.WHITE, new Coordinate(4,7)));
		board.setPieceToCoordinate(new Coordinate(5,7), new Bishop("WBishop","Bishop",Color.WHITE, new Coordinate(5,7)));
		board.setPieceToCoordinate(new Coordinate(6,7), new Knight("WKnight","Knight",Color.WHITE, new Coordinate(6,7)));
		board.setPieceToCoordinate(new Coordinate(7,7), new Rook("WRook","Rook",Color.WHITE, new Coordinate(7,7)));
		for (int i=0; i<X; i++)
			board.setPieceToCoordinate(new Coordinate(i,6), new Pawn("WPawn","Pawn",Color.WHITE, new Coordinate(i,6)));
		*/
		new Rook("BRook","Rook",Color.BLACK, new Coordinate(0,0)).setCoordinate(new Coordinate(0,0));
		new Knight("BKnight","Knight",Color.BLACK, new Coordinate(1,0)).setCoordinate(new Coordinate(1,0));
		new Bishop("BBishop","Bishop",Color.BLACK, new Coordinate(2,0)).setCoordinate(new Coordinate(2,0));
		new Queen("BQueen","Queen",Color.BLACK, new Coordinate(3,0)).setCoordinate(new Coordinate(3,0));
		new King("BKing","King",Color.BLACK, new Coordinate(4,0)).setCoordinate(new Coordinate(4,0));
		new Bishop("BBishop","Bishop",Color.BLACK, new Coordinate(5,0)).setCoordinate(new Coordinate(5,0));
		new Knight("BKnight","Knight",Color.BLACK, new Coordinate(6,0)).setCoordinate(new Coordinate(6,0));
		new Rook("BRook","Rook",Color.BLACK, new Coordinate(7,0)).setCoordinate(new Coordinate(7,0));
		for (int i=0; i<X; i++)
			new Pawn("BPawn","Pawn",Color.BLACK, new Coordinate(i,1)).setCoordinate(new Coordinate(i,1));
		
		new Rook("WRook","Rook",Color.WHITE, new Coordinate(0,7)).setCoordinate(new Coordinate(0,7));
		new Knight("WKnight","Knight",Color.WHITE, new Coordinate(1,7)).setCoordinate(new Coordinate(1,7));
		new Bishop("WBishop","Bishop",Color.WHITE, new Coordinate(2,7)).setCoordinate(new Coordinate(2,7));
		new Queen("WQueen","Queen",Color.WHITE, new Coordinate(3,7)).setCoordinate(new Coordinate(3,7));
		new King("WKing","King",Color.WHITE, new Coordinate(4,7)).setCoordinate(new Coordinate(4,7));
		new Bishop("WBishop","Bishop",Color.WHITE, new Coordinate(5,7)).setCoordinate(new Coordinate(5,7));
		new Knight("WKnight","Knight",Color.WHITE, new Coordinate(6,7)).setCoordinate(new Coordinate(6,7));
		new Rook("WRook","Rook",Color.WHITE, new Coordinate(7,7)).setCoordinate(new Coordinate(7,7));
		for (int i=0; i<X; i++)
			new Pawn("WPawn","Pawn",Color.WHITE, new Coordinate(i,6)).setCoordinate(new Coordinate(i,6));
		
		for(int j=0; j<Y; j++) {
			for(int i=0; i<X; i++) {
				if(j==0 || j==1) path = "img/B";
				else if(j==6 || j==7) path = "img/W";

				if(j==0 || j==7) {     
					if(i==0 || i==7) file = "Rook.jpg";
					if(i==1 || i==6) file = "Knight.jpg";
					if(i==2 || i==5) file = "Bishop.jpg";
					if(i==3) file = "Queen.jpg";
					if(i==4) file = "King.jpg";
					box= new ImageIcon(path+file);
					button[i][j].setIcon(new ImageIcon(box.getImage().getScaledInstance(
							45, 45, java.awt.Image.SCALE_SMOOTH)));
				}
				else if(j==1 || j==6) {
					file = "pawn.jpg";
					box = new ImageIcon(path+file);
					button[i][j].setIcon(new ImageIcon(box.getImage().getScaledInstance(
							45, 45, java.awt.Image.SCALE_SMOOTH)));
				}
				panel.add(button[i][j]);
			}
		}
		//System.out.println(board.toString());
	}

	public static void resetCells(Set<Coordinate> coords) {
		if (coords != null) {
			for (Coordinate c: coords){
				int x = c.getX();
				int y = c.getY();
				if ((x+y)%2==0) button[x][y].setBackground(Color.WHITE);
				else button[x][y].setBackground(brown);  
			}
		}
	}

	public void addMenu() {
		JMenuBar menuBar = new JMenuBar();
		JMenu file = new JMenu("File");

		file.setMnemonic(KeyEvent.VK_F);
		file.getAccessibleContext().setAccessibleDescription("File menu");
		menuBar.add(file);

		menuNew = new JMenuItem("New Game", KeyEvent.VK_N);
		menuNew.addActionListener(this);
		file.add(menuNew);

		menuExit = new JMenuItem("Exit", KeyEvent.VK_X);
		menuExit.addActionListener(this);
		file.add(menuExit);


		frame.setJMenuBar(menuBar);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == menuExit) System.exit(0);
		if (e.getSource() == PButton1){
			comp= new Player(Color.black);
			//user= new Player(Color.white);
			JOptionPane.showMessageDialog(null, "You are playing as White.");
			introFrame.setVisible(false);
		}
		if (e.getSource() == PButton2){
			introFrame.setVisible(false);
		}
		if (e.getSource() == knight) 	promote("Knight");
		if (e.getSource() == bishop) 	promote("Bishop");
		if (e.getSource() == rook) 		promote("Rook");
		if (e.getSource() == queen) 	promote("Queen");

		for (int j=0; j<Y; j++) {
			for (int i=0; i<X; i++) {
				if(e.getSource() == button[i][j]) {	// button clicked at i,j
					Piece p = board.getPiece(i, j);

					if (button[i][j].getBackground()== Color.GREEN){ // move the currentP
						// move the currentP to i, j				// currentP is the piece we will move
						if(isValid(currentP, i, j)){	// checks to see if moves takes you out of check
							movePiece(currentP, i, j);
							highlightMove(lastMove, new Coordinate(i,j));
						}
						else {
							JOptionPane.showMessageDialog(null, "You must move out of check.");
							return;
						}
						
					} else if (p != null) {		// clicked on a piece
						if (whiteTurn == (p.getColor() == Color.WHITE)) {

							Set<Coordinate> coords = p.getPossibleCoordinates();

							if (!(p.isSelected())) {	// selecting piece, turn on highlighting
								if(somethingSelected) return;
								p.setSelected(true);
								currentP= p;
								somethingSelected = true;
								button[i][j].setBackground(Color.YELLOW);
								if (coords != null){
									for (Coordinate c: coords) {
										button[c.getX()][c.getY()].setBackground(Color.GREEN);
									}
								}
							}
							else { // unselecting piece, turn off highlighting
								p.setSelected(false);
								somethingSelected = false;
								if ((i+j)%2 == 0) button[i][j].setBackground(Color.WHITE); 
								else button[i][j].setBackground(brown); 
								resetCells(coords);
							}
						} else JOptionPane.showMessageDialog(null, "Please wait for your turn.");
					}
					if (comp!= null && !whiteTurn){
						Grid g= board;
						Move compMove= comp.searchMove(g, Color.BLACK);
						Player.count--;
						if (isValid(compMove.p, compMove.c.getX(), compMove.c.getY())){
							movePiece(compMove.p, compMove.c);
							highlightMove(lastMove, compMove.c);
						}
						else JOptionPane.showMessageDialog(null, "Computer must move out of check");
					}
					return;
				}
			}
		}
	}

	public static void movePiece(Piece cp, int i, int j) {		
		Coordinate lastC= cp.getCoordinate();
		Set<Coordinate> coords= cp.getPossibleCoordinates();
		coords.add(lastC);
		cp.moveTo(new Coordinate(i,j));
		String path= null;
		String file= null;
		ImageIcon box;
		if (cp.getColor()== Color.BLACK) path= "img/B";
		else if (cp.getColor()== Color.WHITE) path= "img/W";
		if (cp.getType()== "Rook") file= "Rook.jpg";
		else if (cp.getType()== "Knight") file= "Knight.jpg";
		else if (cp.getType()== "Pawn") file= "Pawn.jpg";
		else if (cp.getType()== "Bishop") file= "Bishop.jpg";
		else if (cp.getType()== "Queen") file= "Queen.jpg";
		else if (cp.getType()== "King") file= "King.jpg";
		box= new ImageIcon(path+file);
		button[i][j].setIcon(new ImageIcon(box.getImage().getScaledInstance(
				45, 45, java.awt.Image.SCALE_SMOOTH)));
		button[lastC.getX()][lastC.getY()].setIcon(null);
		resetCells(coords);
		somethingSelected= false;
		currentP.setSelected(false);
		board.setPieceToCoordinate(lastC, null);

		// keep track of this move
		lastMove.oldCoords = lastC;
		lastMove.p = cp;
		

		if (Pawn.enPassant){
			if (whiteTurn)
			{
				button[cp.getCoordinate().getX()][cp.getCoordinate().getY()+1].setIcon(null);
				board.setPieceToCoordinate(new Coordinate(cp.getCoordinate().getX(), cp.getCoordinate().getY()+1), null);
			}
			else {
				button[cp.getCoordinate().getX()][cp.getCoordinate().getY()-1].setIcon(null);
				board.setPieceToCoordinate(new Coordinate(cp.getCoordinate().getX(), cp.getCoordinate().getY()-1), null);
			}
		}
		Pawn.enPassant= false;

		checkCheck();
		whiteTurn = !whiteTurn;
		checkCheck();

		
		if(cp.getType()=="Pawn") {
			if((cp.getCoordinate().getY()==0 && cp.getColor()==Color.WHITE) ||
					 (cp.getCoordinate().getY()==7 && cp.getColor()==Color.BLACK))
				promoFrame.setVisible(true);
		}
	}

	/**
	 * move a Piece to Coordinate
	 * @param cp
	 * @param c
	 */
	public static void movePiece(Piece cp, Coordinate c) {
		movePiece(cp, c.getX(), c.getY());
	}

	public static boolean isCheck() {
		Set<Coordinate> opp = new HashSet<Coordinate>();

		for (int i=0; i<X; i++) {
			for (int j=0; j<Y; j++) {
				Piece p = board.getPiece(i, j);
				if (p != null) {
					if(whiteTurn) {
						if(p.getColor() == Color.WHITE && p.getType() == "King") {
							kingCoords = p.getCoordinate(); 
						}
						if(p.getColor() == Color.BLACK) {
							opp.addAll(p.getPossibleCoordinates());
						}
					} else {
						if(p.getColor() == Color.BLACK && p.getType() == "King") {
							kingCoords = p.getCoordinate(); 
						}
						if(p.getColor() == Color.WHITE) {
							opp.addAll(p.getPossibleCoordinates());
						}
					}
				}
			}
		}

		for(Coordinate c:opp) {
			if (c.equals(kingCoords))
				return true;
		}

		return false;
	}
	
	public static boolean isCheckMate(){
		Set<Coordinate> opp = new HashSet<Coordinate>();
		if (isCheck()){
			for (int i=0; i<X; i++) {
				for (int j=0; j<Y; j++) {
					Piece p = board.getPiece(i, j);
					if (p != null) {
						if(whiteTurn) {
							if(p.getColor() == Color.BLACK) {
								opp.addAll(p.getPossibleCoordinates());
							}
						} else {
							if(p.getColor() == Color.WHITE) {
								opp.addAll(p.getPossibleCoordinates());
							}
						}
					}
				}
			}
			for (Coordinate c: board.getPiece(kingCoords).getPossibleCoordinates()){
				if (!(opp.contains(c)))
					return false;
			}
			
			// check if pieces can block
			
			
			for (int i=0; i<X; i++) {
				for (int j=0; j<Y; j++) {
					Piece p = board.getPiece(i, j);
					if (p != null) {
						if (((p.getColor() == Color.WHITE && whiteTurn) 
								|| (p.getColor() == Color.black && !whiteTurn)) 
								&& p.getType() != "King") {
							if (p.getPossibleCoordinates() != null) {
								for(Coordinate c: p.getPossibleCoordinates()) {
									Coordinate old = p.getCoordinate();
									
									Piece checkP = board.getPiece(c);
										
									//board.setPieceToCoordinate(c, p);
									p.setCoordinate(c);
									board.setPieceToCoordinate(old, null);
									
									boolean b = isCheck();
									//board.setPieceToCoordinate(old, p);
									p.setCoordinate(old);
									if (checkP!=null)
										checkP.setCoordinate(c);
									else
										board.setPieceToCoordinate(c, checkP);
										
									if(!b) return false;			
								}
							}
						}
					}
				}
			}
			
			return true;
		}
		else return false;
	}
	
	public boolean isValid(Piece p, int i, int j) {
		Piece op = board.getPiece(i, j);
		Coordinate currentCoords = p.getCoordinate();
		
		//board.setPieceToCoordinate(new Coordinate(i, j), p);
		p.setCoordinate(new Coordinate(i,j));
		board.setPieceToCoordinate(currentCoords, null);
		
		if(p.getType().equals("King")) 
			kingCoords = p.getCoordinate();
		
		boolean b = isCheck();
		
		//board.setPieceToCoordinate(currentCoords, p);
		p.setCoordinate(currentCoords);
		if (op!= null)
			op.setCoordinate(new Coordinate(i,j));
		else
			board.setPieceToCoordinate(new Coordinate(i, j), op);
		
		kingCoords = p.getCoordinate();
		
		return !b;
	}
	
	public void promoPawn() {
		
		jp = new JPanel();
		//jp.add(new JTextField("Promote your pawn!"));
		knight = new JButton("Knight");	knight.addActionListener(this);	jp.add(knight);	
		bishop = new JButton("Bishop");	bishop.addActionListener(this); jp.add(bishop);
		rook = new JButton("Rook");		rook.addActionListener(this);	jp.add(rook);
		queen = new JButton("Queen");	queen.addActionListener(this);	jp.add(queen);
		
		promoFrame = new JFrame("Pawn Promotion");
		promoFrame.add(jp);
		promoFrame.setSize(200, 100);
		promoFrame.setLocation(400,300);  
	}
	public void promote(String str) {
		ImageIcon box;
		String colorstr = null;
		Color color = lastMove.p.getColor();
		
		
		if (color == Color.BLACK) colorstr = "B";
		else if (lastMove.p.getColor()== Color.WHITE) colorstr = "W";
		
		String path= "img/"+colorstr;
		String file = str+".jpg";
		Piece p = null;
		
		int x = lastMove.p.getCoordinate().getX();
		int y = lastMove.p.getCoordinate().getY();
		Coordinate c = new Coordinate(x, y);
		
		
		if(str=="Knight") p = new Knight(colorstr+str, str, color, c);
		else if(str=="Bishop") p = new Bishop(colorstr+str, str, color, c);
		else if(str=="Rook") p = new Rook(colorstr+str, str, color, c);
		else if(str=="Queen") p = new Queen(colorstr+str, str, color, c);
		
		
		p.setCoordinate(c);
		box= new ImageIcon(path+file);
		
		button[x][y].setIcon(new ImageIcon(box.getImage().getScaledInstance(
				45, 45, java.awt.Image.SCALE_SMOOTH)));
		
		promoFrame.setVisible(false);
		checkCheck();
		
	}
	
	public static void checkCheck() {
		if (isCheck()){
			if (isCheckMate()){
				String lost= "";
				if (board.getPiece(kingCoords).getColor()== Color.BLACK) lost= "Black";
				else lost="White";
				JOptionPane.showMessageDialog(null, "Game Over! " + lost + " has lost.");
			}
			else {
				button[kingCoords.getX()][kingCoords.getY()].setBackground(Color.red);
				JOptionPane.showMessageDialog(null, "You have been checked!");
			}
		} else if((kingCoords.getX()+kingCoords.getY())%2==0) 
			button[kingCoords.getX()][kingCoords.getY()].setBackground(Color.WHITE);
			else button[kingCoords.getX()][kingCoords.getY()].setBackground(brown);
	}
	
	public void highlightMove(LastMove last, Coordinate now){
		lastCoords.add(last.oldCoords); 
		lastCoords.add(now);
		resetCells(lastCoords);
		button[last.oldCoords.getX()][last.oldCoords.getY()].setBackground(Color.BLUE);
		button[now.getX()][now.getY()].setBackground(Color.CYAN);
	}
	
}